<?php
// vim: ts=4 sw=4 fdm=marker
/**
 * Coffee Framework

 * @category   CF
 * @package    CF_util
 * @author     그네 <Jung Sik, Park> <ccooffeee at hotmail dot com>
 * @copyright  Copyright (c) 2011 Jung Sik, Park <ccooffeee at hotmail dot com>
 * @license    doc/LICENSE    Based New BSD License
 * @version    $Id: paging.php,v 0.1 2011/10/11 ccooffeee Exp $

 * LICENSE

 * 본 프로그램은 New BSD License 를 기본으로 하고 있지만 약간 다른 제약조건을 가지고 있습니다. 
 * 함께 제공된 license file 인  doc/LICENSE 를 꼭 확인하시길 바랍니다.

 * This Source is subject to the New BSD License with SOME CONSTRAINT that is boudled
 * with this package in the file doc/LICENSE 
 */


// Util Paging


class CF_util_paging
{
// {{{ properties
	private $value = array();
	private $modified = false;
	private $_tmp = null;
// }}}

// {{{ constructor (array arrayVal = array())
	public function __construct (array $arr = array())
	{
		$this->__set('total', isset($arr['total']) ? $arr['total'] : 0);
		$this->__set('currentPage', isset($arr['currentPage']) ? $arr['currentPage'] : 1);
		$this->__set('rows', isset($arr['rows']) ? $arr['rows'] : 1);
		$this->__set('block', isset($arr['block']) ? $arr['block'] : 1);
		$this->__set('pageString', isset($arr['pageString']) ? $arr['pageString'] : 'page');
		$this->__set('firstQueryString', isset($arr['firstQueryString']) ? $arr['firstQueryString'] : '');
		$this->__set('lastQueryString', isset($arr['lastQueryString']) ? $arr['lastQueryString'] : '');
		$this->__set('linkType', isset($arr['linkType']) ? $arr['linkType'] : '');
		$this->__set('center', isset($arr['center']) ? $arr['center'] : false);
		$this->__set('partition', isset($arr['partition']) ? $arr['partition'] : false);
		$this->__set('partInfo', isset($arr['partInfo']) ? $arr['partInfo'] : null);
	}
// }}}


// {{{ CF_util_paging set (string name, mixed value)
	public function set($name, $value)
	{
		$this->__set($name, $value);

		return $this;
	}
// }}}

// {{{ array getAll (void)
	public function getAll ()
	{
		return (object)array('total' => $this->__get('total'),
					'currentPage' => $this->__get('currentPage'),
					'totalPage' => $this->__get('totalPage'),
					'prevLink' => $this->__get('prevLink'),
					'nextLink' => $this->__get('nextLink'),
					'firstLink' => $this->__get('firstLink'),
					'lastLink' => $this->__get('lastLink'),
					'pageList' => $this->__get('pageList'),
					'limit' => $this->__get('limit'),
					'offset' => $this->__get('offset'),
					'positions' => $this->__get('positions')
			);
	}
// }}}


// {{{ magic methods : __get, __set
	public function __set($name, $value)
	{
		$_val = $this->get($name);

		switch($name) {
			case 'total':
				$this->_set($name, (int)$value >= 0 ? (int)$value : 0);
				break;
			case 'currentPage':
			case 'rows':
			case 'block':
				$this->_set($name, (int)$value > 0 ? (int)$value : 1);
				break;
			case 'pageString':
			case 'firstQueryString':
			case 'lastQueryString':
				$value = (string)$value;

				if($name == 'pageString' && $value == '')
					$value = 'page';

				$this->_set($name, $value);
				break;
			case 'linkType':
				$this->_set($name, $value == 'pretty' ? 'pretty' : '');
				break;
			case 'center':
			case 'partition':
				$this->_set($name, $value === true ? true : false);
				break;
			case 'partInfo':
				if(!is_array($value)) return;
 
				foreach($value as $part => $count) {
					if(!is_int($part) || $part < 1 || !is_int($count))
						return;
				}

				$this->_set($name, $value);
				break;
		}

		if($_val != $this->get($name)) $this->modified = true;
	}


	public function __get($name)
	{
		$this->process();

		return $this->get($name);
	}
// }}}


// {{{ private methods
	// {{{ mixed get (string name)
	private function get($name)
	{
		return isset($this->value[$name]) ? $this->value[$name] : null;
	}
	// }}}
	// {{{ void _set (string name, mixed value)
	private function _set($name, $value)
	{
		$this->value[$name] = $value;
	}
	// }}}
	// {{{ void process (void)
	private function process()
	{
		if(!$this->modified) return;

		$this->_set('totalPage', ceil($this->get('total') / $this->get('rows')));

		if($this->get('totalPage') > 0 && $this->get('currentPage') > $this->get('totalPage'))
			$this->_set('currentPage', $this->get('totalPage'));

		$this->_set('limit', $this->get('rows'));
		$this->_set('offset', ($this->get('currentPage') - 1) * $this->get('rows'));


		$this->_process();
		$this->_setPageList();
		$this->_setPartPosition();


		$enablePrev = ($this->_tmp['start'] > 1) ? true : false;
		$enableNext = ($this->_tmp['end'] < $this->get('totalPage')) ? true : false;

		$this->_set('prevLink', $enablePrev ? $this->_getLinkString($this->_tmp['prev']) : null);
		$this->_set('nextLink', $enableNext ? $this->_getLinkString($this->_tmp['next']) : null);
		$this->_set('firstLink', $enablePrev ? $this->_getLinkString(1) : null);
		$this->_set('lastLink', $enableNext ? $this->_getLinkString($this->get('totalPage')) : null);


		$this->modified = false;
	}
	// }}}
	// {{{ void _process (void)
	private function _process()
	{
		if($this->get('total') == 0) {
			$this->_tmp = array('start' => 0, 'end' => 0,
								'prev' => 0, 'next' => 0);
			return;
		}

		if($this->get('center') === true) {
			$_center = intval($this->get('block') / 2);
			$_mod = $this->get('block') % 2 ? true : false;

			if($this->get('currentPage') <= $_center)
				$start = 1;
			elseif((($this->get('totalPage') - $this->get('currentPage')) < $_center) && $_mod > 0)
				$start = $this->get('totalPage') - $this->get('block') + 1;
			elseif((($this->get('totalPage') - $this->get('currentPage') + 1) < $_center) && $_mod == 0)
				$start = $this->get('totalPage') - $this->get('block') + 1;
			else $start = $this->get('currentPage') - $_center;

			$prev = $this->get('currentPage') - $this->get('block');
			$next = $this->get('currentPage') + $this->get('block');
		}
		else {
			$start = (intval($this->get('currentPage') / $this->get('block')) * $this->get('block')) + 1;
			if(!($this->get('currentPage') % $this->get('block')))
				$start -= $this->get('block');

			$prev = $start - $this->get('block');
			$next = $start + $this->get('block');
		}
		if($start < 1) $start = 1;

		$end = $start + $this->get('block') - 1;
		if($end > $this->get('totalPage')) $end = $this->get('totalPage');
		if($prev < 1) $prev = 1;
		if($next > $this->get('totalPage')) $next = $this->get('totalPage');

		$this->_tmp = array('start' => $start, 'end' => $end,
							'prev' => $prev, 'next' => $next);
	}
	// }}}
	// {{{ void _setPageList (void)
	private function _setPageList()
	{
		if(!is_array($this->_tmp) || $this->_tmp['start'] == 0 || $this->_tmp['end'] == 0)
			return;

		for($i = $this->_tmp['start']; $i <= $this->_tmp['end']; $i++) {
			$pageList[] = array(
							'pageNum' => $i,
							'link' => $this->_getLinkString($i),
							'current'=> (!strcmp($this->get('currentPage'), $i))
			);
		}

		$count = count($pageList);
		$pageList[$count - 1]['end'] = 1;


		$this->_set('pageList', $pageList);
	}
	// }}}
	// {{{ void _setPartPosition (void)
	private function _setPartPosition()
	{
		if(!$this->get('partition') || !is_array($this->get('partInfo')))
			return;

		$start = $this->get('offset');
		$end = $this->get('offset') + $this->get('limit');

		$sum = 0;
		$found = false;
		$pos = array();
		$_offset = 0;

		foreach($this->get('partInfo') as $part => $count) {
			$sum += $count;
			if($sum > $start) $found = true;

			if($found) {
				$pos[] = $part;
				if($_offset == 0)
					$_offset = $this->get('offset') + $count - $sum;
			}
			if($sum >= $end) break;
		}

		if(count($pos) == 0) return;


		$this->_set('positions', $pos);
		$this->_set('offset', $_offset);
	}
	// }}}
	// {{{ string _getLinkString (integer pageNumber)
	private function _getLinkString ($num)
	{
		$delim = $this->get('linkType') == 'pretty' ? '/' : '&amp;';
		$link = array();

		if($this->get('firstQueryString'))
			$link[] = $this->get('firstQueryString');
		$link[] = $delim == '/' ? $num : $this->get('pageString').'='.$num;
		if($this->get('lastQueryString'))
			$link[] = $this->get('lastQueryString');

		return implode($delim, $link);
	}
	// }}}
// }}}
}
?>
